//~ #define SKIPIT
#include "utils.h"

#if  defined(Q_OS_WIN)
//~ #include "winbase.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#define WDebugString(x) OutputDebugString( __STR__(__LINE__)": " ),OutputDebugString( x ),OutputDebugString( "\n" )
//~ #define ODS(sz) DebugString(sz)
//~ WINBASEAPI void WINAPI OutputDebugStringA(LPCSTR);
//~ DebugBreak()  _asm { int 0x03 }
#else
#define WDebugString(x)
#endif /* WINDOWS **/
#include <QtDebug>
#define QD qDebug() << __FILE__ << __LINE__ << ":"




char * Sversioninfo = new char [4096];
char * Spluginfo = new char [4096];
char * Swidginfo = new char [4096];
char * Svalue = new char [4096];
char * Spros = new char [4096];
char * SprosEror = new char [4096];


#ifndef HAS_STRLCPY

//strl from euphoria
//~ size_t eu_strlcpy(char *dest, const char *src, size_t maxlen)
//~ {
//~ strncpy(dest, src, maxlen);
//~ dest[maxlen-1] = '\0';
//~ return strlen(src);
//~ }

//4msysgit\compat\gitstrlcpy
size_t strlcpy(char *dest, const char *src, size_t size)
{
	size_t ret = strlen(src);

	if (size)
	{
		size_t len = (ret >= size) ? size - 1 : ret;
		memcpy(dest, src, len);
		dest[len] = '\0';
	}
	return ret;
}

size_t strlcat(char *dest, const char *src, size_t maxlen)
{
	int orig_dest_len = strlen(dest);
	strncat(dest, src, maxlen - 1);
	dest[maxlen-1] = '\0';
	return orig_dest_len + strlen(src);
}

#endif /*HAS_STRLCPY*/


QHash<QString, int> events;
QMap<int, QString> keys;

//idea & code from the guts of eventsview lib
/***************************************************************************
 *   Copyright (C) 2006 by Vladimir Kuznetsov                              *
 *   vovanec@gmail.com                                                     */
void init_events()
{
	Q_INIT_RESOURCE(res);
	QFile file(":events");
	if (!file.open(QIODevice::ReadOnly))
		qWarning("cannot open event translation file");
	QTextStream ts(&file);
	while (!ts.atEnd())
	{
		QString str = ts.readLine();
		QStringList pairs = str.split(" ");
		events[pairs[0]] = pairs[1].toInt();
	}
}
void init_keys()
{

	QFile file(":keys");
	if (!file.open(QIODevice::ReadOnly))
		qWarning("cannot open keys translation file");
	QTextStream ts(&file);
	while (!ts.atEnd())
	{
		QString str = ts.readLine();
		QStringList pairs = str.split(" ");
		bool ok;
		keys[(pairs[1]).toInt(&ok, 16)] = pairs[0];
	}

	QHash<QString, int>::iterator i;
	QStringList names = events.keys();
	qSort(names.begin(), names.end());
}

const char *msgstring(QEvent* event)
{
	static int no = 1;
	if (no)  //only do once on first call
	{
		no = 0;
		init_events();
		init_keys();
	}
	//decide if is key or other event and send the right one
	if (event->type() == QEvent::KeyPress)
	{
		QKeyEvent *ke = static_cast<QKeyEvent*>(event);
		return QString("key: %1").arg(keys[ke->key()]).toAscii().data();
	}
	return events.key(event->type()).toAscii().data();
}

QString buttonFromInteger(Qt::MouseButton btn)
{
	switch (btn)
	{
	case Qt::NoButton:
		return "Qt::NoButton";
	case Qt::LeftButton:
		return "Qt::LeftButton";
	case Qt::RightButton:
		return "Qt::RightButton";
	case Qt::MidButton:
		return "Qt::MidButton";
	case Qt::XButton1:
		return "Qt::XButton1";
	case Qt::XButton2:
		return "Qt::XButton2";
	default:
		return QString::number(btn);
	}
}
QString dropActionFromInteger(Qt::DropAction a)
{
	switch (a)
	{
	case Qt::CopyAction:
		return "Qt::CopyAction";
	case Qt::MoveAction:
		return "Qt::MoveAction";
	case Qt::LinkAction:
		return "Qt::LinkAction";
	case Qt::TargetMoveAction:
		return "Qt::TargetMoveAction";
	case Qt::IgnoreAction:
		return "Qt::IgnoreAction";
	default:
		return QString::number(a);
	}
}


extern "C"
const char *qt_version_info()
{
	QDir path = QDir(".");

	//convert to hex, 40500 for w/4.5beta1
	QString s = QString("minGW -v something  Qt_,%1").arg(QT_VERSION, 0, 16, QLatin1Char(' '));

	qDebug() << qApp->tr("in version_info %1").arg(s);
	//~ qDebug() << qApp->tr(" %1\n").arg(path);
	qDebug() << qApp->tr("currentPath %1\n").arg(QDir::currentPath());
	qDebug() << qApp->tr("homePath %1\n").arg(QDir::homePath());
	qDebug() << qApp->tr("tempPath %1\n").arg(QDir::tempPath());
	qDebug() << QProcess::systemEnvironment().join(",");//~ env()
//~ QCoreApplication::applicationDIrPath
//~ QCoreApplication::applicationFilePath



	//do has phonon
	//this is true even though I definatly have no phon in win9x minGW
	qDebug() << QSound::isAvailable() << "QSound::isAvailable";
	//~ QString user(env.section("GIT_AUTHOR_NAME", 1).section(",", 0, 0).section("=", 1).trimmed());
	//~ qDebug() << Phonon::BackendCapabilities::availableAudioDevices().join(",");

	qDebug() << qt_hasOpenGL() << "hasOpenGL";


	strlcpy(Sversioninfo, static_cast<const char*>(s.toUtf8().data()), 2000);//shareddata
	return Sversioninfo;
}

/*
QT_NO_PLUGIN_CHECK
-qt-sql-plugin
*/
extern "C"
const char *qt_plugin_info()
{
	QDir path = QDir(".");
	QString s = "";
	QStringList ls = QApplication::libraryPaths();

	foreach(QString sl, ls)
	{
		s.append(sl) + QDir::separator(); // (?)? ":":"l";
	}
	qDebug() << qApp->tr(" Qt libraryPaths %1").arg(s);

	strlcpy(Spluginfo, static_cast<const char*>(s.toUtf8().data()), 2000);//shareddata
	return Spluginfo;
}
extern "C"
const char *qt_widget_info(QObject *widget)
{
	QString s = "";
	widget->dumpObjectTree();
	widget->dumpObjectInfo();


	strlcpy(Swidginfo, static_cast<const char*>(s.toUtf8().data()), 2000);//shareddata
	return Swidginfo;
}

extern "C"
QClipboard *qt_clipboard(QApplication *app)
{
	return app->clipboard();
}


extern "C"
const char *qt_text(QObject *widget, const char *mime)
{
	const QMetaObject *mo = widget->metaObject();
	QString kls = mo->className();
	qDebug() << kls << "kls_text";
	// determine if clipboard object send possible mime type
	//don't think I have to wory about a copy or deep copy here?
	if (kls == "QTextEdit"  || kls == "QPlainTextEdit")
	{
		return ((QTextEdit *)widget)->toPlainText().toLatin1().data();
	}
	else if (kls == "QLineEdit")
	{
		return ((QLineEdit *)widget)->text().toLatin1().data();
	}
	else if (kls == "QClipboard")
	{
		return ((QClipboard *)widget)->text().toLatin1().data();
	}
	return "\0";
}

//this barely scratches the surface, need selected rich and on and on
extern "C"
void qt_setText(QObject *widget, const char *t, const char *mime)
{
	const QMetaObject *mo = widget->metaObject();
	QString kls = mo->className();
	qDebug() << kls << "kls_setText";
	// determine if clipboard object send possible mime type
	//maybe should use inherits?
	if (kls == "QTextEdit" || kls == "QPlainTextEdit")
	{
		((QTextEdit *)widget)->setText(QString(t));
		//~ return  (qobject_cast<QTextEdit *>(widget))->setText(QString(t));
	}
	else if (kls == "QLineEdit")
	{
		((QLineEdit *)widget)->setText(QString(t));
	}
	else if (kls == "QClipboard")
	{
		((QClipboard *)widget)->setText(QString(t));
	}
}

// need to add for clipboard and for lneedit, label QPrinter QPicture
extern "C"
void qt_appendText(QObject *widget, const char *t)
{
	const QMetaObject *mo = widget->metaObject();
	QString kls = mo->className();
	qDebug() << kls << "kls_appendText";
	if (kls == "QTextEdit"  || kls == "QPlainTextEdit")
	{
		((QTextEdit *)widget)->append(QString(t));
		//~ return (qobject_cast<QTextEdit *>(widget))->append(QString(t));
	}
	else if (kls == "QLineEdit")
	{
		QString s = ((QLineEdit *)widget)->text();
		((QLineEdit *)widget)->setText(s + QString(t));
	}
	else if (kls == "QClipboard")
	{
		QString s = ((QClipboard *)widget)->text();
		((QClipboard *)widget)->setText(s + QString(t));
	}
}

//may want to send child and make the simpleWidget the parent
//so it inherits all the d&d things?
simpleWidget::simpleWidget(QWidget *parent): QWidget()
{
	//~ w = new QWidget(parent);
	//~ w->installEventFilter(this);
	//~ w->setContextMenuPolicy(Qt::CustomContextMenu);
	//~ w->setObjectName("simpleWidget");
	//~ w->setAcceptDrops(true);
	//seems to hang at eventFilter even if don't set QWidget(parent)
	//after sending a few Polish related 69 74 75
	//if don't try to reparent parent, then it doesn't hang
	//~ parent->setParent(w);
	//~ this = new QWidget(parent);
	installEventFilter(this);
	setContextMenuPolicy(Qt::CustomContextMenu);
	setObjectName("simpleWidget");
	setAcceptDrops(true);
	
	if (parent)
	{
		parent->setParent(this);
	}
}

void simpleWidget::keyPressEvent(QKeyEvent *e)
{
	int key = e->key();
	qDebug() << "simpleWidget::keyPressEvent " << key << msgstring(e);

	//~ if (keyEvent->key() == Qt::Key_Escape)
	//~ emit escapePressed();
	//~ if( e->state() & ControlButton )
	//~ key += CTRL;
	//~ if( e->state() & AltButton )
	//~ key += ALT;
	//~ if( e->state() & MetaButton )
	//~ key += META;
	//~ if( e->state() & ShiftButton )
	//~ key += SHIFT;

	//~ int cmd = keyMap[key];
	//~ if( cmd )
	//~ SendScintilla(cmd);
	//~ else
	//~ QextScintilla::keyPressEvent( e );
}


void simpleWidget::contextMenu(QContextMenuEvent *e)
{
	QMenu* menu = new QMenu(this);
	qDebug() << "simpleWidget::contextMenu";
	//~ menu->addAction("Switch links", this, SLOT(switchLinks()));
	menu->exec(e->globalPos());
	delete menu;
}

simpleWidget::~simpleWidget()
{
	qDebug() << "simpleWidget::~simpleWidget";
}

bool simpleWidget::eventFilter(QObject* object, QEvent* event)
{
	static int i = -1;
	qDebug() << "simpleWidget::eventFilter " << event->type() << msgstring(event);
	//Show context menu on right click.
	if (event->type() == QEvent::ContextMenu)
	{
		contextMenu(static_cast<QContextMenuEvent *>(event));
		return true;
	}
	else   if (event->type() == QEvent::KeyPress)
	{
		keyPressEvent(static_cast<QKeyEvent*>(event));
		//~ QKeyEvent *ke = static_cast<QKeyEvent*>(event);
		//~ if (ke->key() == Qt::Key_Enter ||
		//~ ke->key() == Qt::Key_Return)
		//~ {
		//~ submitChatText();
		//~ return true;
		//~ }
	}
	else if (event->type() == QEvent::ChildRemoved)
	{
	}
	return QWidget::eventFilter(object, event);
}


//~ void MainWindow::dropEvent(QDropEvent *event) {
//~ QList<QUrl> urls = event->mimeData()->urls();
//~ if (urls.isEmpty())
//~ return;

void simpleWidget::dropEvent(QDropEvent *event)
{
	QFileInfo fileInfo;
	QString fileName = event->mimeData()->urls().first().toLocalFile();
	fileInfo.setFile(fileName);
	qDebug() << "simpleWidget::dropEvent";  //dropActionFromInteger(Qt::DropAction a)
	if (fileInfo.isFile())
	{
		qDebug() << "Got drop event. Filename is: " << fileName << "\n";
		//~ setupDocument(fileName);
	}
	event->acceptProposedAction();
}

//~ QDropEvent *event
//~ void PiecesList::dropEvent(QDropEvent *event)
//~ event->mimeData()->hasFormat()
//~ event->setDropAction();
//~ event->accept();
//~ event->ignore();
//~ event->acceptProposedAction();
//~ void QObject::installEventFilter ( QObject * filterObj )

//~ Qt::DropActions supportedDropActions () const;
//~ 


extern "C"
bool qt_acceptDrops(QWidget *widget, int setreset)
{
    
    //if has widget->setDropIndicatorShown(true);

	if (setreset < 0)
	{
		return widget->acceptDrops();
	}
	widget->setAcceptDrops((bool)setreset);
	return widget->acceptDrops();
}


extern "C"
simpleWidget *qt_simpleWidget(QWidget *parent)
{
	return new simpleWidget(parent);
}

extern "C"
QTimer *qt_Timer(QApplication *app)
{
	return new QTimer(app);
}

//~ extern "C"
//~ singleShot *qt_singleShot(QApplication *app)
//~ {
//~ return new singleShot(app);
//~ }

extern "C"
bool qt_stopTimer(QTimer *t)
{
	if (!t)
	{
		return 0;
	}
	t->stop();
	return 1;
}

extern "C"
bool qt_startTimer(QTimer *t)
{
	if (!t)
	{
		return 0;
	}
	t->start();
	return 1;
}

extern "C"
bool qt_setIntervalTimer(QTimer *t, int n)
{
	if (!t)
	{
		return 0;
	}
	t->setInterval(n);
	return 1;
}


//~ QSettings settings("starrunner.ini", QSettings::IniFormat);
//adding sync I think so any changes are recorded or read before use.
extern "C"
QSettings *qts_settings(const char *F, int I, QWidget *parent)
{
	QSettings *s = new QSettings(QString(F), QSettings::Format(I), parent);

	//should check for error condition
	s->sync();
	return s;
}

extern "C"
void qts_remove(QSettings *S, const char *K)
{
	S->sync();
	return S->remove(QString(K));
}

extern "C"
bool qts_contains(QSettings *S, const char *K)
{
	S->sync();
	return S->contains(QString(K));
}

extern "C"
void qts_beginGroup(QSettings *S, const char *G)
{
	S->sync();
	S->beginGroup(G);
	S->sync();
}

extern "C"
void qts_endGroup(QSettings *S)
{
	S->sync();
	S->endGroup();
	S->sync();
}

//for now values only char * set/get
extern "C"
bool qts_setValue(QSettings *S, const char *K, const char *V)
{
	S->sync();
	S->setValue(K, V);
	S->sync();

	return 1;
}


extern "C"
const char *qts_value(QSettings *S, const char *K)
{
	S->sync();
	//~ QString V = qobject_cast<QString>(S->value(K));
	QVariant V = S->value(K);

	strlcpy(Svalue, static_cast<const char*>(V.toString().toUtf8().data()), 2000);//shareddata
	return Svalue;
}


extern "C"
QProcess *qt_Process(QObject *parent)
{
	return  new QProcess(parent);
}



//~ startDetached
//~ const QString & program, const QStringList & arguments, OpenMode mode = ReadWrite
extern "C"
bool qt_startProcess(QProcess *pros, const char *prog, char **args)
{
	int idx = 0;
	char *value = args[idx];
	QStringList arguments;
	//~ foreach(QString s, args) arguments << s; //not quite possible

	//~ qDebug() << qApp->tr("in pros->start prog=%1 args=%2").arg(prog).arg(arguments);
	qDebug() << qApp->tr("in pros->start prog=%1 ").arg(prog);
	//wonder is arguments empty a problem?
	if (!args)
	{
		pros->start(prog);  //, arguments unset a problem
	}
	else
	{
		while (value != NULL)
		{
			arguments << static_cast<const char*>(args[idx]);
			qDebug() << qApp->tr("in start while idx=%1 val=%2").arg(idx).arg(value);
			idx += 1;
			value = args[idx];
		}

		pros->start(prog);
	}
	qDebug() << qApp->tr("past pros->start prog=%1 ").arg(prog);
	//actually check is startable mayube or return any error?
	return 1;
}

//wonder if this is too much of a can of worms
//may have to wrap everything and let the user handle it
extern "C"
const char *qt_readProcess(QProcess *pros)
{
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	while (!pros->waitForStarted(5000))
	{
		qDebug() << qApp->tr("wait4Started  ");
		//~ Sleep(20);
	}
	QApplication::restoreOverrideCursor();
	QByteArray B = pros->readAllStandardOutput();

	if (pros->exitStatus() != QProcess::NormalExit)
	{
		qDebug() << "Bad exit";
	}



	strlcpy(Spros, static_cast<const char*>(B.constData()), 2000);//shareddata
	return Spros;
}

extern "C"
bool qt_closeProcess(QProcess *pros)
{
	pros->close();
	return 1;
}
extern "C"
bool qt_killProcess(QProcess *pros)
{
	//~ qDebug() << "finished" << pros->exitCode << pros->exitStatus;
	pros->kill();
	return 1;
}
int qt_errorProcess(QProcess *pros)
{

	return static_cast<int >(pros->error());
}
extern "C"
const char *qt_errorStringProcess(QProcess *pros)
{

	//~ if(pros->state() ==0 )
	QString S = pros->errorString();

	strlcpy(SprosEror, static_cast<const char*>(S.toUtf8().data()), 2000);//shareddata
	return SprosEror;
}

//~ const char *qt_runCmd()



//need a few more things, exit error env read write  startDetached

FILE *stdFILE(int c)
{
	if (c == 0)        return stdin;
	if (c == 1)        return stdout;
	if (c == 2)        return stderr;

	return NULL;
}
